﻿using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.IO.Compression;
using System.Windows.Forms;
using System.Diagnostics;
using System.ComponentModel;
using System.Security.Cryptography;
using System.Security.Principal;
using System.Runtime.InteropServices;
using System.Security.Permissions;
using System.Reflection;
using System.Configuration;
using System.Security;
using System.Threading;
using System.Net;
using System.Xml;
using System.Text.RegularExpressions;
using System.Collections.Specialized;
using System.Data.SqlClient;


namespace AutoUpdate
{
    /// <summary>
    /// This is a Reader that reads the files baseStream to get an 
    /// entry in the zip archive one after another.The zip entry contains 
    /// information about the file name, size, compressed size, CRC, etc.
    /// It includes support for GZIP and DEFLATE methods of compression.
    /// <summary>
    public class ZipReader
    {
        [DllImport("advapi32.dll", SetLastError = true)]
        public static extern bool LogonUser(String lpszUsername, String lpszDomain, String lpszPassword,
            int dwLogonType, int dwLogonProvider, ref IntPtr phToken);

        public System.Configuration.Configuration csSection = null;
        private Stream zipStream;		//The zip stream which is instantiated
        //and closed after every operation

        private string zipName;			//Name given to the archive
        private Stream baseStream;		//The base stream from which the header 
        //and compressed data are read

        private Int16 numberOfFiles;
        private byte method;
        private List<String> listaExecute = null;
        private List<String> listaScripturi = null;

        System.Security.Cryptography.MD5CryptoServiceProvider md5;
        //Required for checking CRC
        private FrmAutoUpdate frmAU = null;
        /// <summary>
        /// Creates a new Zip input stream, reading a zip archive.
        /// </summary>
        public ZipReader(FrmAutoUpdate _frm, Stream fileStream, string name, List<String> _listaExecute, List<String> _listaScripturi, System.Configuration.Configuration _csSection)
        {
            csSection = _csSection;
            frmAU = _frm;
            listaExecute = _listaExecute;
            listaScripturi = _listaScripturi;
            zipName = name;
            baseStream = fileStream;
            numberOfFiles = -1;
            method = 255;
            md5 = new System.Security.Cryptography.MD5CryptoServiceProvider();
        }

        /// <summary>
        /// Reads the super header
        /// Super header structure:
        ///		number of files - 2 byte
        ///		method of compression - 1 byte
        /// </summary>
        /// <exception cref="ArgumentOutOfRangeException">
        /// Thrown if the super header is tampered
        /// </exception>
        /// 
        private void ReadSuperHeader()
        {
            numberOfFiles = ReadLeInt16();
            method = ReadLeByte();
            if (method != ZipConstants.DEFLATE &&
                method != ZipConstants.GZIP)
                throw new ArgumentOutOfRangeException();
        }

        private int ReadBuf(byte[] outBuf, int length)
        {
            return baseStream.Read(outBuf, 0, length);
        }

        /// <summary>
        /// Read a byte from baseStream.
        /// </summary>
        private byte ReadLeByte()
        {
            int c= baseStream.ReadByte();
            return (byte)c;
        }

        /// <summary>
        /// Read an unsigned short baseStream little endian byte order.
        /// </summary>
        private Int16 ReadLeInt16()
        {
            Int16 c = (Int16)(ReadLeByte() | (ReadLeByte() << 8));
            return c;
        }

        /// <summary>
        /// Read an int baseStream little endian byte order.
        /// </summary>
        private Int32 ReadLeInt32()
        {
            return (UInt16)ReadLeInt16() | ((UInt16)ReadLeInt16() << 16);
        }

        private string ConvertToString(byte[] data)
        {
            return System.Text.Encoding.ASCII.GetString(data, 0, data.Length);
        }

        /// <summary>
        /// Open the next entry from the zip archive, and return its 
        /// description. The method expects the pointer to be intact.
        /// </summary>
        private ZipEntry GetNextEntry()
        {
            ZipEntry currentEntry = null;
            try
            {
                Int32 size = ReadLeInt32();
                if (size == -1)
                    return new ZipEntry(String.Empty);

                Int32 csize = ReadLeInt32();
                byte[] crc = new byte[16];
                ReadBuf(crc, crc.Length);

                Int32 dostime = ReadLeInt32();
                Int16 nameLength = ReadLeInt16();

                byte[] buffer = new byte[nameLength];
                ReadBuf(buffer, nameLength);
                string name = ConvertToString(buffer);

                currentEntry = new ZipEntry(name);
                currentEntry.Size = size;
                currentEntry.CompressedSize = csize;
                currentEntry.SetCrc(crc);
                currentEntry.DosTime = dostime;
            }
            catch (ArgumentException)
            {
                ZipConstants.ShowError(ZipConstants.ArgumentError);
            }
            catch (ObjectDisposedException)
            {
                ZipConstants.ShowError(ZipConstants.CloseError);
            }
            return currentEntry;
        }

        /// <summary>
        /// Writes the uncompressed data into the filename in the 
        /// entry. It instantiates a memory stream which will serve 
        /// as a temp store and decompresses it using Gzip Stream or
        /// Deflate stream
        /// </summary>
        private Boolean WriteUncompressedFile(ZipEntry entry, string completePath,ListView lV)
        {
            Boolean ret = true;
            MemoryStream ms = new MemoryStream();
            try
            {
                byte[] b = new byte[entry.CompressedSize];
                baseStream.Read(b, 0, (int)entry.CompressedSize);
                if (CheckCRC(entry.GetCrc(), b))
                    ms.Write(b, 0, b.Length);
                ms.Seek(0, SeekOrigin.Begin);
                if (method == ZipConstants.DEFLATE)
                    zipStream = new DeflateStream(ms,
                        CompressionMode.Decompress, false);
                else if (method == ZipConstants.GZIP)
                    zipStream = new GZipStream(ms, CompressionMode.Decompress,
                        false);

                int index = entry.Name.LastIndexOf(ZipConstants.BackSlash);
                string name = completePath + entry.Name.Substring(index + 1);
                if (name.ToLower().Contains("autoupdate.exe"))
                    name = name.Replace(".exe", ".new");

                ListViewItem item1 = lV.Items.Add(name);
                item1.SubItems.Add("OK");
                item1.ImageIndex = 1;
                //item1.SubItems.Add("Indisponibil");

                ///nu proceseaza fisierele de log
                if (name.ToLower().Contains("trace.log"))
                {
                    b = new byte[entry.Size];
                    zipStream.Read(b, 0, (int)entry.Size);
                    return true;
                }
                // daca exista il sterge
                if (File.Exists(name))
                {
                     FileInfo fi =new FileInfo(name);
                     if(fi.Attributes != FileAttributes.Normal)
                        fi.Attributes = FileAttributes.Normal;
                     Trace.WriteLine("[" + DateTime.Now.ToString() + "] Delete file: " + name);
                     File.Delete(name);
                }
                Trace.WriteLine("[" + DateTime.Now.ToString() + "] Start write file: " + name);
                FileStream rewrite = new FileStream(name, FileMode.Create);
                b = new byte[entry.Size];
                zipStream.Read(b, 0, (int)entry.Size);
                rewrite.Write(b, 0, (int)entry.Size);
                rewrite.Close();
                Trace.WriteLine("[" + DateTime.Now.ToString() + "] End write file: " + name);
                if (listaScripturi!=null)
                    foreach(String fis in listaScripturi)
                    {
                        if (name.Contains(fis))
                        {
                            Trace.WriteLine("[" + DateTime.Now.ToString() + "] Se vor rula scripturile: ");
                            if (frmAU != null)
                            {
                                Trace.WriteLine("[" + DateTime.Now.ToString() + "] AutoUpdate: " + name);
                                ret |= frmAU.RunScript(name);
                            }
                            break;
                        }
                    }

                if (listaExecute != null)
                    
                    foreach (String fis in listaExecute)
                    {
                        Trace.WriteLine("[" + DateTime.Now.ToString() + "] Se vor executa fisierele: " + fis);
                        //"{[(" + paramCmd + ")]}([{" + userStr + "}])[({" + parolaStr + "})]");
                        int poz = fis.IndexOf("{[(");
                        if (poz < 0)
                            continue;
                        String NameExe = fis.Substring(0, poz);
                        String param = String.Empty, rest = fis.Substring(poz + 3);
                        poz = rest.IndexOf(")]}");
                        param = rest.Substring(0, poz);

                        String userStr = String.Empty, parolaStr = String.Empty;
                        rest = rest.Substring(poz + 3);

                        poz = rest.IndexOf("([{");
                        rest = rest.Substring(3);
                        poz = rest.IndexOf("}])");
                        userStr = rest.Substring(0, poz);

                        poz = rest.IndexOf("[({");
                        rest = rest.Substring(poz + 3);
                        poz = rest.IndexOf("})]");
                        parolaStr = rest.Substring(0, poz);


                        if (name.Contains(NameExe))
                        {
                            string passPhrase = "Pas5pr@se";        // can be any string
                            string saltValue = "s@1tValue";        // can be any string
                            string hashAlgorithm = "SHA1";             // can be "MD5"
                            int passwordIterations = 2;                  // can be any number
                            string initVector = "@1B2c3D4e5F6g7H8"; // must be 16 bytes
                            int keySize = 256;                // can be 192 or 128
                            String plainText = Decrypt(parolaStr, passPhrase,
                                                    saltValue, hashAlgorithm,
                                                    passwordIterations, initVector, keySize);
                            Start(name, param, userStr, plainText);
                            break;
                        }
                    }
                Application.DoEvents();

                
            }
            catch (IOException ex)
            {
                ZipConstants.ShowError(ex.ToString());
                ret = false;
            }
            catch (ArgumentException)
            {
                ZipConstants.ShowError(ZipConstants.ArgumentError);
                ret = false;
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
                ret = false;
            }
            finally
            {
                zipStream.Close();
                ms.Close();
            }
            return ret;
        }

        
       

        public void Start(String nume_mod, String param, String user, String parola)
        {
            if (!nume_mod.Contains(".exe"))
                return;
            try
            {
                //Test();
                Cursor.Current = Cursors.WaitCursor;
                //presupunem ca nu are parametrii
                Process myProcess = new Process();
                myProcess.StartInfo = new ProcessStartInfo(nume_mod);
                /*myProcess.StartInfo.UseShellExecute = false;
                int pozS = user.IndexOf('\\');
                if (pozS < 0)
                    myProcess.StartInfo.Domain = Environment.MachineName;
                else
                    myProcess.StartInfo.Domain = user.Substring(0, pozS);
                myProcess.StartInfo.UserName = user.Substring(pozS+1);
                

                IntPtr tokenHandle = new IntPtr(0);
                IntPtr dupeTokenHandle = new IntPtr(0);

			
                const int LOGON32_PROVIDER_DEFAULT = 0;
                //This parameter causes LogonUser to create a primary token.
                const int LOGON32_LOGON_INTERACTIVE = 2;

                tokenHandle = IntPtr.Zero;
 
                // Call LogonUser to obtain a handle to an access token.
                bool returnValue = LogonUser(myProcess.StartInfo.UserName, myProcess.StartInfo.Domain, parola, 
                LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT,
                ref tokenHandle);
                UseProperties(tokenHandle);
                // Define the string value to assign to a new secure string.
                char[] chars = parola.ToCharArray();
                 myProcess.StartInfo.Password = new System.Security.SecureString();
                for (int i = 0; i < chars.Length; i++)
                     myProcess.StartInfo.Password.AppendChar(chars[i]);*/

                myProcess.StartInfo.WorkingDirectory = Directory.GetCurrentDirectory();
                myProcess.StartInfo.Verb = "runas";
                myProcess.StartInfo.Arguments = param;
                
                
                myProcess.Start();
			
                myProcess.WaitForExit();
                Cursor.Current = Cursors.Default;
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }
        }


        private void Test()
        {
            // Retrieve the Windows account token for the current user.
            IntPtr logonToken = LogonUser();

            // Constructor implementations.
            IntPtrConstructor(logonToken);
            IntPtrStringConstructor(logonToken);
            IntPtrStringTypeConstructor(logonToken);
            IntPrtStringTypeBoolConstructor(logonToken);

            // Property implementations.
            UseProperties(logonToken);

            // Method implementations.
            GetAnonymousUser();
            ImpersonateIdentity(logonToken);

      //       MessageBox.Show("This sample completed successfully; " +
      //          "press Enter to exit.");
      //      Console.ReadLine();
        }

        // Create a WindowsIdentity object for the user represented by the
        // specified Windows account token.
        private static void IntPtrConstructor(IntPtr logonToken)
        {
            // Construct a WindowsIdentity object using the input account token.
            WindowsIdentity windowsIdentity = new WindowsIdentity(logonToken);

            MessageBox.Show("Created a Windows identity object named " +
                windowsIdentity.Name + ".");
        }


        // Create a WindowsIdentity object for the user represented by the
        // specified account token and authentication type.
        private static void IntPtrStringConstructor(IntPtr logonToken)
        {
            // Construct a WindowsIdentity object using the input account token 
            // and the specified authentication type.
            string authenticationType = "WindowsAuthentication";
            WindowsIdentity windowsIdentity =
                new WindowsIdentity(logonToken, authenticationType);

            MessageBox.Show("Created a Windows identity object named " +
                windowsIdentity.Name + ".");
        }

        // Create a WindowsIdentity object for the user represented by the
        // specified account token, authentication type, and Windows account
        // type.
        private static void IntPtrStringTypeConstructor(IntPtr logonToken)
        {
            // Construct a WindowsIdentity object using the input account token,
            // and the specified authentication type, and Windows account type.
            string authenticationType = "WindowsAuthentication";
            WindowsAccountType guestAccount = WindowsAccountType.Guest;
            WindowsIdentity windowsIdentity =
                new WindowsIdentity(logonToken, authenticationType, guestAccount);

            MessageBox.Show("Created a Windows identity object named " +
                windowsIdentity.Name + ".");
        }

        // Create a WindowsIdentity object for the user represented by the
        // specified account token, authentication type, Windows account type, and
        // Boolean authentication flag.
        private static void IntPrtStringTypeBoolConstructor(IntPtr logonToken)
        {
            // Construct a WindowsIdentity object using the input account token,
            // and the specified authentication type, Windows account type, and
            // authentication flag.
            string authenticationType = "WindowsAuthentication";
            WindowsAccountType guestAccount = WindowsAccountType.Guest;
            bool isAuthenticated = true;
            WindowsIdentity windowsIdentity = new WindowsIdentity(
                logonToken, authenticationType, guestAccount, isAuthenticated);

            MessageBox.Show("Created a Windows identity object named " +
                windowsIdentity.Name + ".");
        }

        // Access the properties of a WindowsIdentity object.
        private static void UseProperties(IntPtr logonToken)
        {
            WindowsIdentity windowsIdentity = new WindowsIdentity(logonToken);
            string propertyDescription = "The Windows identity named ";

            // Retrieve the Windows logon name from the Windows identity object.
            propertyDescription += windowsIdentity.Name;

            // Verify that the user account is not considered to be an Anonymous
            // account by the system.
            if (!windowsIdentity.IsAnonymous)
            {
                propertyDescription += " is not an Anonymous account";
            }

            // Verify that the user account has been authenticated by Windows.
            if (windowsIdentity.IsAuthenticated)
            {
                propertyDescription += ", is authenticated";
            }

            // Verify that the user account is considered to be a System account
            // by the system.
            if (windowsIdentity.IsSystem)
            {
                propertyDescription += ", is a System account";
            }

            // Verify that the user account is considered to be a Guest account
            // by the system.
            if (windowsIdentity.IsGuest)
            {
                propertyDescription += ", is a Guest account";
            }

            // Retrieve the authentication type for the 
            String authenticationType = windowsIdentity.AuthenticationType;

            // Append the authenication type to the output message.
            if (authenticationType != null)
            {
                propertyDescription += (" and uses " + authenticationType);
                propertyDescription += (" authentication type.");
            }

            MessageBox.Show(propertyDescription);


            SecurityIdentifier si = windowsIdentity.Owner;
            // Display the SIDs for the groups the current user belongs to.
            IdentityReferenceCollection irc = windowsIdentity.Groups;
            String rez = String.Empty;
            foreach (IdentityReference ir in irc)
                rez +=ir.Value + ";";
            
  
            TokenImpersonationLevel token = windowsIdentity.ImpersonationLevel;

            MessageBox.Show("The SID for the owner is : " + si.ToString() + "\nDisplay the SIDs for the groups the current user belongs to." + rez +
                "\nThe impersonation level for the current user is : " + token.ToString());
        }

        // Retrieve the account token from the current WindowsIdentity object
        // instead of calling the unmanaged LogonUser method in the advapi32.dll.
        private static IntPtr LogonUser()
        {
            IntPtr accountToken = WindowsIdentity.GetCurrent().Token;
            MessageBox.Show( "Token number is: " + accountToken.ToString());

            return accountToken;
        }

        // Get the WindowsIdentity object for an Anonymous user.
        private static void GetAnonymousUser()
        {
            // Retrieve a WindowsIdentity object that represents an anonymous
            // Windows user.
            WindowsIdentity windowsIdentity = WindowsIdentity.GetAnonymous();
        }

        // Impersonate a Windows identity.
        private static void ImpersonateIdentity(IntPtr logonToken)
        {
            // Retrieve the Windows identity using the specified token.
            WindowsIdentity windowsIdentity = new WindowsIdentity(logonToken);

            // Create a WindowsImpersonationContext object by impersonating the
            // Windows identity.
            WindowsImpersonationContext impersonationContext =
                windowsIdentity.Impersonate();

            MessageBox.Show("Name of the identity after impersonation: "
                + WindowsIdentity.GetCurrent().Name + ".");
            MessageBox.Show(windowsIdentity.ImpersonationLevel.ToString());
            // Stop impersonating the user.
            impersonationContext.Undo();

            // Check the identity name.
            Console.Write("Name of the identity after performing an Undo on the");
            MessageBox.Show(" impersonation: " +
                WindowsIdentity.GetCurrent().Name);
        }
   

        public String Encrypt(String plainText,String passPhrase,String saltValue,
                                 string hashAlgorithm,
                                 int passwordIterations,
                                 string initVector,
                                 int keySize)
        {
            // Convert strings into byte arrays.
            // Let us assume that strings only contain ASCII codes.
            // If strings include Unicode characters, use Unicode, UTF7, or UTF8 
            // encoding.
            byte[] initVectorBytes = Encoding.ASCII.GetBytes(initVector);
            byte[] saltValueBytes = Encoding.ASCII.GetBytes(saltValue);

            // Convert our plaintext into a byte array.
            // Let us assume that plaintext contains UTF8-encoded characters.
            byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText);

            // First, we must create a password, from which the key will be derived.
            // This password will be generated from the specified passphrase and 
            // salt value. The password will be created using the specified hash 
            // algorithm. Password creation can be done in several iterations.
            PasswordDeriveBytes password = new PasswordDeriveBytes(
                                                            passPhrase,
                                                            saltValueBytes,
                                                            hashAlgorithm,
                                                            passwordIterations);

            // Use the password to generate pseudo-random bytes for the encryption
            // key. Specify the size of the key in bytes (instead of bits).
            byte[] keyBytes = password.GetBytes(keySize / 8);

            // Create uninitialized Rijndael encryption object.
            RijndaelManaged symmetricKey = new RijndaelManaged();

            // It is reasonable to set encryption mode to Cipher Block Chaining
            // (CBC). Use default options for other symmetric key parameters.
            symmetricKey.Mode = CipherMode.CBC;

            // Generate encryptor from the existing key bytes and initialization 
            // vector. Key size will be defined based on the number of the key 
            // bytes.
            ICryptoTransform encryptor = symmetricKey.CreateEncryptor(
                                                             keyBytes,
                                                             initVectorBytes);

            // Define memory stream which will be used to hold encrypted data.
            MemoryStream memoryStream = new MemoryStream();

            // Define cryptographic stream (always use Write mode for encryption).
            CryptoStream cryptoStream = new CryptoStream(memoryStream,
                                                         encryptor,
                                                         CryptoStreamMode.Write);
            // Start encrypting.
            cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);

            // Finish encrypting.
            cryptoStream.FlushFinalBlock();

            // Convert our encrypted data from a memory stream into a byte array.
            byte[] cipherTextBytes = memoryStream.ToArray();

            // Close both streams.
            memoryStream.Close();
            cryptoStream.Close();

            // Convert encrypted data into a base64-encoded string.
            string cipherText = Convert.ToBase64String(cipherTextBytes);

            // Return encrypted string.
            return cipherText;
        }

        /// <summary>
        /// Decrypts specified ciphertext using Rijndael symmetric key algorithm.
        /// </summary>
        /// <param name="cipherText">
        /// Base64-formatted ciphertext value.
        /// </param>
        /// <param name="passPhrase">
        /// Passphrase from which a pseudo-random password will be derived. The
        /// derived password will be used to generate the encryption key.
        /// Passphrase can be any string. In this example we assume that this
        /// passphrase is an ASCII string.
        /// </param>
        /// <param name="saltValue">
        /// Salt value used along with passphrase to generate password. Salt can
        /// be any string. In this example we assume that salt is an ASCII string.
        /// </param>
        /// <param name="hashAlgorithm">
        /// Hash algorithm used to generate password. Allowed values are: "MD5" and
        /// "SHA1". SHA1 hashes are a bit slower, but more secure than MD5 hashes.
        /// </param>
        /// <param name="passwordIterations">
        /// Number of iterations used to generate password. One or two iterations
        /// should be enough.
        /// </param>
        /// <param name="initVector">
        /// Initialization vector (or IV). This value is required to encrypt the
        /// first block of plaintext data. For RijndaelManaged class IV must be
        /// exactly 16 ASCII characters long.
        /// </param>
        /// <param name="keySize">
        /// Size of encryption key in bits. Allowed values are: 128, 192, and 256.
        /// Longer keys are more secure than shorter keys.
        /// </param>
        /// <returns>
        /// Decrypted string value.
        /// </returns>
        /// <remarks>
        /// Most of the logic in this function is similar to the Encrypt
        /// logic. In order for decryption to work, all parameters of this function
        /// - except cipherText value - must match the corresponding parameters of
        /// the Encrypt function which was called to generate the
        /// ciphertext.
        /// </remarks>
        public String Decrypt(String cipherText,String passPhrase, String saltValue,
                                     String hashAlgorithm,int passwordIterations,
                                     string initVector, int keySize)
        {
            // Convert strings defining encryption key characteristics into byte
            // arrays. Let us assume that strings only contain ASCII codes.
            // If strings include Unicode characters, use Unicode, UTF7, or UTF8
            // encoding.
            byte[] initVectorBytes = Encoding.ASCII.GetBytes(initVector);
            byte[] saltValueBytes = Encoding.ASCII.GetBytes(saltValue);

            // Convert our ciphertext into a byte array.
            byte[] cipherTextBytes = Convert.FromBase64String(cipherText);

            // First, we must create a password, from which the key will be 
            // derived. This password will be generated from the specified 
            // passphrase and salt value. The password will be created using
            // the specified hash algorithm. Password creation can be done in
            // several iterations.
            PasswordDeriveBytes password = new PasswordDeriveBytes(passPhrase, saltValueBytes,hashAlgorithm,passwordIterations);

                                                            
            // Use the password to generate pseudo-random bytes for the encryption
            // key. Specify the size of the key in bytes (instead of bits).
            byte[] keyBytes = password.GetBytes(keySize / 8);

            // Create uninitialized Rijndael encryption object.
            RijndaelManaged symmetricKey = new RijndaelManaged();

            // It is reasonable to set encryption mode to Cipher Block Chaining
            // (CBC). Use default options for other symmetric key parameters.
            symmetricKey.Mode = CipherMode.CBC;

            // Generate decryptor from the existing key bytes and initialization 
            // vector. Key size will be defined based on the number of the key 
            // bytes.
            ICryptoTransform decryptor = symmetricKey.CreateDecryptor(keyBytes,initVectorBytes);
                                                             

            // Define memory stream which will be used to hold encrypted data.
            MemoryStream memoryStream = new MemoryStream(cipherTextBytes);

            // Define cryptographic stream (always use Read mode for encryption).
            CryptoStream cryptoStream = new CryptoStream(memoryStream, decryptor,CryptoStreamMode.Read);
                                                          

            // Since at this point we don't know what the size of decrypted data
            // will be, allocate the buffer long enough to hold ciphertext;
            // plaintext is never longer than ciphertext.
            byte[] plainTextBytes = new byte[cipherTextBytes.Length];

            // Start decrypting.
            int decryptedByteCount = cryptoStream.Read(plainTextBytes,
                                                       0,
                                                       plainTextBytes.Length);

            // Close both streams.
            memoryStream.Close();
            cryptoStream.Close();

            // Convert decrypted data into a string. 
            // Let us assume that the original plaintext string was UTF8-encoded.
            string plainText = Encoding.UTF8.GetString(plainTextBytes,
                                                       0,
                                                       decryptedByteCount);

            // Return decrypted string.   
            return plainText;
        }
    

   
    /*private void Test(string[] args)
    {
        string plainText = "Hello, World!";    // original plaintext

        string passPhrase = "Pas5pr@se";        // can be any string
        string saltValue = "s@1tValue";        // can be any string
        string hashAlgorithm = "SHA1";             // can be "MD5"
        int passwordIterations = 2;                  // can be any number
        string initVector = "@1B2c3D4e5F6g7H8"; // must be 16 bytes
        int keySize = 256;                // can be 192 or 128

        MessageBox.Show(String.Format("Plaintext : {0}", plainText));

        string cipherText = RijndaelSimple.Encrypt(plainText,
                                                    passPhrase,
                                                    saltValue,
                                                    hashAlgorithm,
                                                    passwordIterations,
                                                    initVector,
                                                    keySize);

        MessageBox.Show(String.Format("Encrypted : {0}", cipherText));

        plainText = RijndaelSimple.Decrypt(cipherText,
                                                    passPhrase,
                                                    saltValue,
                                                    hashAlgorithm,
                                                    passwordIterations,
                                                    initVector,
                                                    keySize);

        MessageBox.Show(String.Format("Decrypted : {0}", plainText));
    }*/


        /// <summary>
        /// Extracts all the entries in the list of entries
        ///	</summary>
        /// <param name="zipentries">
        ///	List of all the zip entries. Can be empty.
        /// </param>

        public Boolean ExtractAll(List<ZipEntry> zipEntries, string startPath, ListView lV)
        {
            Boolean ret = true;
            try
            {
                //DirectoryInfo dir = new DirectoryInfo(startPath + zipName);
                Trace.WriteLine("[" + DateTime.Now.ToString() + "]{AutoUpdate} start ExtractAll(): " + startPath);
                Trace.Flush();
                DirectoryInfo dir = new DirectoryInfo(startPath);
                if (!dir.Exists)
                    dir.Create();

                int jump = 3;
                baseStream.Seek(jump, SeekOrigin.Begin);

                foreach (ZipEntry entry in zipEntries)
                {
                    Trace.WriteLine("[" + DateTime.Now.ToString() + "]{AutoUpdate} process entry: " + entry.Name);
                    Trace.Flush();
                    int index1 = entry.Name.IndexOf(ZipConstants.BackSlash);
                    index1 = entry.Name.IndexOf(ZipConstants.BackSlash, index1+1);
                    index1 = entry.Name.IndexOf(ZipConstants.BackSlash, index1+1);
                    //int index2 = entry.Name.LastIndexOf(ZipConstants.BackSlash);
                    int index2 = entry.Name.LastIndexOf(ZipConstants.BackSlash);
                    string relPath = entry.Name.Substring(index1 + 1,index2 - index1);
                    //string relPath = entry.Name.Substring(index2 + 1);
                    if (index1 == 0)
                        relPath = String.Empty;

                    if (relPath.Length != 0)
                        dir.CreateSubdirectory(relPath);

                    jump = ZipConstants.FixedHeaderSize + entry.NameLength;
                    baseStream.Seek(jump, SeekOrigin.Current);
                    ret |= WriteUncompressedFile(entry, startPath + ZipConstants.BackSlash + relPath,lV);
                }
                /*CompressionForm.statusMessage = String.Format(
                    System.Threading.Thread.CurrentThread.CurrentUICulture,
                    ZipConstants.ExtractMessage, startPath + zipName +
                    ZipConstants.BackSlash);*/
            }
            catch (IOException)
            {
                ZipConstants.ShowError(ZipConstants.IOError);
                return false;
            }
            catch (OutOfMemoryException)
            {
                ZipConstants.ShowError(ZipConstants.MemoryError);
                return false;
            }
            return ret;
        }

        /// <summary>
        /// Extracts the specified entry
        ///	</summary>
        /// <param name="entry">
        ///	The entry that is to be extracted.Cannot be null
        /// </param>
        /// <param name="jump">
        ///	The offset from the SeekOrigin.Begin at which the 
        /// comrpessed data is located
        /// </param>

        public void Extract(ZipEntry entry, long jump, string startPath)
        {
            try
            {
                DirectoryInfo dir = new DirectoryInfo(startPath + zipName);
                if (!dir.Exists)
                    dir.Create();
                int index1 = entry.Name.IndexOf(ZipConstants.BackSlash);
                int index2 = entry.Name.LastIndexOf(ZipConstants.BackSlash);
                string relPath = entry.Name.Substring(index1 + 1,
                    index2 - index1);
                if (index1 == 0)
                    relPath = String.Empty;

                if (relPath.Length != 0)
                    dir.CreateSubdirectory(relPath);
                baseStream.Seek(jump, SeekOrigin.Begin);
                jump = ZipConstants.FixedHeaderSize + entry.NameLength;
                baseStream.Seek(jump, SeekOrigin.Current);

                WriteUncompressedFile(entry, startPath + zipName + ZipConstants.BackSlash + relPath,null);
                /*CompressionForm.statusMessage = String.Format(
                    System.Threading.Thread.CurrentThread.CurrentUICulture,
                    ZipConstants.ExtractMessage, startPath + zipName +
                    ZipConstants.BackSlash);*/
            }
            catch (IOException)
            {
                ZipConstants.ShowError(ZipConstants.IOError);
            }
            catch (OutOfMemoryException)
            {
                ZipConstants.ShowError(ZipConstants.MemoryError);
            }
        }

        /// <summary>
        /// Gets all the entries in the file 
        /// </summary>
        /// <returns>
        ///	List of all the zip entries
        /// </returns> 


        public List<ZipEntry> GetAllEntries()
        {
            List<ZipEntry> headers = null;
            try
            {
                if (method == 255 || numberOfFiles == -1)
                {
                    baseStream.Seek(0, SeekOrigin.Begin);
                    ReadSuperHeader();
                }
                headers = new List<ZipEntry>(numberOfFiles);
                baseStream.Seek(3, SeekOrigin.Begin);
                for (int i = 0; i < numberOfFiles; ++i)
                {
                    ZipEntry entry = GetNextEntry();
                    headers.Add(entry);
                    baseStream.Seek(entry.CompressedSize, SeekOrigin.Current);
                }
            }
            catch (IOException)
            {
                ZipConstants.ShowError(ZipConstants.IOError);
            }

            return headers;
        }
        /// <summary>
        /// Gets the method of compression of the archive.
        /// </summary>
        /// <returns>
        /// the ZipConstants.Deflate or ZipConstants.Gzip
        /// </returns>
        public byte Method
        {
            get
            {
                return method;
            }
        }

        //Check the CRC of the byte array and return true if check successful
        //false otherwise
        private bool CheckCRC(byte[] crc, byte[] data)
        {
            byte[] newCrc = md5.ComputeHash(data);
            for (int i = 0; i < crc.Length; ++i)
            {
                if (crc[i] != newCrc[i])
                    return false;
            }
            return true;
        }
    }
}
